package xyz.bali16.module.follow.service;

import com.gitee.starblues.bootstrap.annotation.AutowiredType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.stereotype.Service;
import xyz.bali16.application.entity.User;
import xyz.bali16.application.service.UserService;
import xyz.bali16.module.follow.utils.FollowRedisKeyUtil;

import java.util.*;

@Service
public class FollowServiceImpl implements FollowService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    @AutowiredType(AutowiredType.Type.PLUGIN_MAIN)
    private UserService userService;


    @Override
    public void follow(String userId, String targetUserId) {
        redisTemplate.execute(new SessionCallback() {
            @Override
            public Object execute(RedisOperations operations) throws DataAccessException {
                // 处理关注的人列表与粉丝列表
                String followeeKey = FollowRedisKeyUtil.getFolloweeKey(userId);
                String followerKey = FollowRedisKeyUtil.getFollowerKey(targetUserId);
                operations.multi();
                // 关注的人列表增加目标
                operations.opsForZSet().add(followeeKey, targetUserId, System.currentTimeMillis());
                // 粉丝列表中增加userId
                operations.opsForZSet().add(followerKey, userId, System.currentTimeMillis());
                return operations.exec();
            }
        });
    }

    @Override
    public void unfollow(String userId, String targetUserId) {
        redisTemplate.execute(new SessionCallback() {
            @Override
            public Object execute(RedisOperations operations) throws DataAccessException {
                String followeeKey = FollowRedisKeyUtil.getFolloweeKey(userId);
                String followerKey = FollowRedisKeyUtil.getFollowerKey(targetUserId);
                operations.multi();
                operations.opsForZSet().remove(followeeKey, targetUserId);
                operations.opsForZSet().remove(followerKey, userId);
                return operations.exec();
            }
        });
    }

    @Override
    public long findFolloweeCount(String userId) {
        String followeeKey = FollowRedisKeyUtil.getFolloweeKey(userId);
        return redisTemplate.opsForZSet().zCard(followeeKey);
    }

    @Override
    public long findFollowerCount(String userId) {
        String followerKey = FollowRedisKeyUtil.getFollowerKey(userId);
        return redisTemplate.opsForZSet().zCard(followerKey);
    }

    @Override
    public boolean hasFollowed(String userId, String followeeUserId) {
        String followeeKey = FollowRedisKeyUtil.getFolloweeKey(userId);
        System.out.println( redisTemplate.opsForZSet().score(followeeKey,followeeUserId) );
        return redisTemplate.opsForZSet().score(followeeKey,followeeUserId) != null;
    }

    @Override
    public List<Map<String, Object>> findFollowees(String userId, int offset, int limit) {
        String followeeKey = FollowRedisKeyUtil.getFolloweeKey(userId);
        Set<String> targetIds = redisTemplate.opsForZSet().reverseRange(followeeKey, offset, offset + limit - 1);
        System.out.println(targetIds);
        if (targetIds == null) {
            return null;
        }

        List<Map<String, Object>> list = new ArrayList<>();
        for (String targetId : targetIds) {
            Map<String, Object> map = new HashMap<>();
            User user = userService.getById(targetId);
            map.put("user", user);
            Double score = redisTemplate.opsForZSet().score(followeeKey, targetId);
            map.put("followTime", new Date(score.longValue()));
            list.add(map);
        }

        return list;
    }

    @Override
    public List<Map<String, Object>> findFollowers(String userId, int offset, int limit) {
        String followerKey = FollowRedisKeyUtil.getFollowerKey(userId);
        Set<String> targetIds = redisTemplate.opsForZSet().reverseRange(followerKey, offset, offset + limit - 1);
        System.out.println(targetIds);
        if (targetIds == null) {
            return null;
        }

        List<Map<String, Object>> list = new ArrayList<>();
        for (String targetId : targetIds) {
            Map<String, Object> map = new HashMap<>();
            User user = userService.getById(targetId);
            map.put("user", user);
            Double score = redisTemplate.opsForZSet().score(followerKey, targetId);
            map.put("followTime", new Date(score.longValue()));
            list.add(map);
        }

        return list;
    }
}
